﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System.Linq;

namespace HNet
{
    public class ClientClass
    {
        //KCP
        private uint _conv = 0;

        public uint Conv
        {
            get { return _conv; }
        }

        public KCP ClientKcp = null;

        //接收队列
        private SwitchQueue<byte[]> _recvQueue = new SwitchQueue<byte[]>(128);

        public Action<byte[]> InputBytes = null;

        public byte[] ReadBuff = new byte[BufferSize];
        private const int BufferSize = 1024;

        //Socket和接收缓冲区
        private Socket _socket;

        //UDP
        private UdpClient _udpClient;

        private IPEndPoint _ipEndPoint;
        private IPEndPoint _sevrEndPoint;

        //发送地址和端口
        private IPEndPoint _selfEndPoint;

        //连接，返回成功或者失败

        public bool TcpConnetion(string host, int port)
        {
            //Connect
            try
            {
                //Socket
                _socket = new Socket(AddressFamily.InterNetwork,
                    SocketType.Stream, ProtocolType.Tcp);

                _socket.Connect(host, port);
                _selfEndPoint = (IPEndPoint)_socket.LocalEndPoint;
                _selfEndPoint = new IPEndPoint(_selfEndPoint.Address, _selfEndPoint.Port);
                NetLog.C("地址 " + _socket.LocalEndPoint);

                //记录
                _sevrEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
                //Recv
                _socket.BeginReceive(ReadBuff, 0, BufferSize, SocketFlags.None, TcpReceiveCb, null);

                return true;
            }
            catch (SocketException e)
            {
                NetLog.C("服务器连接失败，" + e);
                return false;
            }
        }

        //接收回调
        private void TcpReceiveCb(IAsyncResult ar)
        {
            try
            {
                //count是接收数据的大小
                int count = _socket.EndReceive(ar);

                //收到Conv并构造
                if (_conv == 0)
                {
                    //Conv = System.BitConverter.ToUInt32(readBuff, 0);
                    KCP.ikcp_decode32u(ReadBuff, 0, ref _conv);

                    NetLog.C("收到Conv：" + _conv);
                    _selfEndPoint = new IPEndPoint(_selfEndPoint.Address, _selfEndPoint.Port + 1);
                    _sevrEndPoint.Port += (int)_conv;
                    UdpConnect();

                    ClientKcp = new KCP(_conv, (buf, size) =>
                    {
                        //NetLog.C("UDP 发送消息" + size);
                        _udpClient.Send(buf, size);
                    });

                    ClientKcp.NoDelay(1, NetController.Instance.Interval, 2, 1);

                    _socket.BeginReceive(ReadBuff, 0, BufferSize, SocketFlags.None, TcpReceiveCb, null);
                    return;
                }

                //mRecvQueue.Push(readBuff.Take(count).ToArray());

                //继续接收
                _socket.BeginReceive(ReadBuff, 0, BufferSize, SocketFlags.None, TcpReceiveCb, null);
            }
            catch (Exception e)
            {
                NetLog.C("AcceptCb链接中断:" + e);
                _socket.Close();
            }
        }

        public void UdpConnect()
        {
            _udpClient = new UdpClient(_selfEndPoint);
            _udpClient.Connect(_sevrEndPoint);

            _udpClient.BeginReceive(ReceiveCallback, this);
            NetLog.C("UDP监听" + _selfEndPoint + "，连接" + _sevrEndPoint);
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            Byte[] data = (_ipEndPoint == null)
                ? _udpClient.Receive(ref _ipEndPoint)
                : _udpClient.EndReceive(ar, ref _ipEndPoint);

            //NetLog.C("UDP 收到消息" + data.Length);

            if (null != data)
                _recvQueue.Push(data);

            if (_udpClient != null)
            {
                // try to receive again.
                _udpClient.BeginReceive(ReceiveCallback, this);
            }
        }

        //发送数据
        public void Send(byte[] bytes)
        {
            try
            {
                //socket.Send(bytes);
                ClientKcp.Send(bytes);
            }
            catch
            {
                // ignored
            }
        }

        public void Update(uint current)
        {
            if (ClientKcp != null)
            {
                //mRecvQueue.Switch();

                while (!_recvQueue.Empty())
                {
                    var buf = _recvQueue.Pop();

                    ClientKcp.Input(buf);
                }

                for (var size = ClientKcp.PeekSize(); size > 0; size = ClientKcp.PeekSize())
                {
                    var buffer = new byte[size];
                    if (ClientKcp.Recv(buffer) > 0)
                    {
                        // string str = System.Text.Encoding.UTF8.GetString(buffer);
                        //数据处理
                        if (InputBytes != null)
                        {
                            InputBytes(buffer);
                        }

                        /*   if (recvStr.Length > 300) recvStr = "";
                           recvStr += str + "\n";
                           //Debug.Log((UInt32)(Convert.ToInt64(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds) & 0xffffffff));
                           */
                    }
                }

                ClientKcp.Update(current);
            }
        }

        public void Close()
        {
            _socket.Close();
            _socket = null;
            if (_udpClient != null)
            {
                _udpClient.Close();
            }

            _udpClient = null;
            _recvQueue.Clear();
            ClientKcp = null;
        }
    }
}